home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / enscript.4 / enscript / enscript-1.4.0 / intl / l10nflist.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-06-06  |  9.3 KB  |  382 lines

  1. /* Copyright (C) 1995, 1996 Free Software Foundation, Inc.
  2. This file is part of the GNU C Library.
  3. Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
  4.  
  5. The GNU C Library is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU Library General Public License as
  7. published by the Free Software Foundation; either version 2 of the
  8. License, or (at your option) any later version.
  9.  
  10. The GNU C Library is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13. Library General Public License for more details.
  14.  
  15. You should have received a copy of the GNU Library General Public
  16. License along with the GNU C Library; see the file COPYING.LIB.  If
  17. not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  18. Boston, MA 02111-1307, USA.  */
  19.  
  20. #ifdef HAVE_CONFIG_H
  21. # include <config.h>
  22. #endif
  23.  
  24. #if defined _LIBC && (defined __ARGZ_COUNT || defined __ARGZ_STRINGIFY)
  25. # include <argz.h>
  26. #endif
  27. #include <ctype.h>
  28.  
  29. #if defined STDC_HEADERS || defined _LIBC
  30. # include <stdlib.h>
  31. #endif
  32.  
  33. #if defined HAVE_STRING_H || defined _LIBC
  34. # include <string.h>
  35. #else
  36. # include <strings.h>
  37. #endif
  38. #if !HAVE_STRCHR && !defined _LIBC
  39. # ifndef strchr
  40. #  define strchr index
  41. # endif
  42. #endif
  43.  
  44. #include "loadinfo.h"
  45.  
  46. /* @@ end of prolog @@ */
  47.  
  48. #ifdef _LIBC
  49. /* Rename the non ANSI C functions.  This is required by the standard
  50.    because some ANSI C functions will require linking with this object
  51.    file and the name space must not be polluted.  */
  52. # define stpcpy(dest, src) __stpcpy(dest, src)
  53. #else
  54. # ifndef HAVE_STPCPY
  55. static char *stpcpy PARAMS ((char *dest, const char *src));
  56. # endif
  57. #endif
  58.  
  59. /* Define function which are usually not available.  */
  60.  
  61. #if !defined _LIBC && !defined __ARGZ_COUNT
  62. /* Returns the number of strings in ARGZ.  */
  63. static size_t __argz_count PARAMS ((const char *argz, size_t len));
  64.  
  65. static size_t
  66. __argz_count (argz, len)
  67.      const char *argz;
  68.      size_t len;
  69. {
  70.   size_t count = 0;
  71.   while (len > 0)
  72.     {
  73.       size_t part_len = strlen (argz);
  74.       argz += part_len + 1;
  75.       len -= part_len + 1;
  76.       count++;
  77.     }
  78.   return count;
  79. }
  80. #endif    /* !_LIBC && !__ARGZ_COUNT */
  81.  
  82. #if !defined _LIBC && !defined __ARGZ_STRINGIFY
  83. /* Make '\0' separated arg vector ARGZ printable by converting all the '\0's
  84.    except the last into the character SEP.  */
  85. static void __argz_stringify PARAMS ((char *argz, size_t len, int sep));
  86.  
  87. static void
  88. __argz_stringify (argz, len, sep)
  89.      char *argz;
  90.      size_t len;
  91.      int sep;
  92. {
  93.   while (len > 0)
  94.     {
  95.       size_t part_len = strlen (argz);
  96.       argz += part_len;
  97.       len -= part_len + 1;
  98.       if (len > 0)
  99.     *argz++ = sep;
  100.     }
  101. }
  102. #endif    /* !_LIBC && !__ARGZ_COUNT */
  103.  
  104. #if !defined _LIBC && !defined __ARGZ_NEXT
  105. static char *
  106. __argz_next (argz, argz_len, entry)
  107.      char *argz;
  108.      size_t argz_len;
  109.      const char *entry;
  110. {
  111.   if (entry)
  112.     {
  113.       if (entry < argz + argz_len)
  114.         entry = strchr (entry, '\0') + 1;
  115.  
  116.       return entry >= argz + argz_len ? NULL : (char *) entry;
  117.     }
  118.   else
  119.     if (argz_len > 0)
  120.       return argz;
  121.     else
  122.       return 0;
  123. }
  124. #endif
  125.  
  126.  
  127. /* Return number of bits set in X.  */
  128. static int pop PARAMS ((int x));
  129.  
  130. static inline int
  131. pop (x)
  132.      int x;
  133. {
  134.   /* We assume that no more than 16 bits are used.  */
  135.   x = ((x & ~0x5555) >> 1) + (x & 0x5555);
  136.   x = ((x & ~0x3333) >> 2) + (x & 0x3333);
  137.   x = ((x >> 4) + x) & 0x0f0f;
  138.   x = ((x >> 8) + x) & 0xff;
  139.  
  140.   return x;
  141. }
  142.  
  143.  
  144. struct loaded_l10nfile *
  145. _nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, mask, language,
  146.             territory, codeset, normalized_codeset, modifier, special,
  147.             sponsor, revision, filename, do_allocate)
  148.      struct loaded_l10nfile **l10nfile_list;
  149.      const char *dirlist;
  150.      size_t dirlist_len;
  151.      int mask;
  152.      const char *language;
  153.      const char *territory;
  154.      const char *codeset;
  155.      const char *normalized_codeset;
  156.      const char *modifier;
  157.      const char *special;
  158.      const char *sponsor;
  159.      const char *revision;
  160.      const char *filename;
  161.      int do_allocate;
  162. {
  163.   char *abs_filename;
  164.   struct loaded_l10nfile *last = NULL;
  165.   struct loaded_l10nfile *retval;
  166.   char *cp;
  167.   size_t entries;
  168.   int cnt;
  169.  
  170.   /* Allocate room for the full file name.  */
  171.   abs_filename = (char *) malloc (dirlist_len
  172.                   + strlen (language)
  173.                   + ((mask & TERRITORY) != 0
  174.                      ? strlen (territory) + 1 : 0)
  175.                   + ((mask & XPG_CODESET) != 0
  176.                      ? strlen (codeset) + 1 : 0)
  177.                   + ((mask & XPG_NORM_CODESET) != 0
  178.                      ? strlen (normalized_codeset) + 1 : 0)
  179.                   + (((mask & XPG_MODIFIER) != 0
  180.                       || (mask & CEN_AUDIENCE) != 0) ?
  181.                      strlen (modifier) + 1 : 0)
  182.                   + ((mask & CEN_SPECIAL) != 0
  183.                      ? strlen (special) + 1 : 0)
  184.                   + ((mask & CEN_SPONSOR) != 0
  185.                      ? strlen (sponsor) + 1 : 0)
  186.                   + ((mask & CEN_REVISION) != 0
  187.                      ? strlen (revision) + 1 : 0)
  188.                   + 1 + strlen (filename) + 1);
  189.  
  190.   if (abs_filename == NULL)
  191.     return NULL;
  192.  
  193.   retval = NULL;
  194.   last = NULL;
  195.  
  196.   /* Construct file name.  */
  197.   memcpy (abs_filename, dirlist, dirlist_len);
  198.   __argz_stringify (abs_filename, dirlist_len, ':');
  199.   cp = abs_filename + (dirlist_len - 1);
  200.   *cp++ = '/';
  201.   cp = stpcpy (cp, language);
  202.  
  203.   if ((mask & TERRITORY) != 0)
  204.     {
  205.       *cp++ = '_';
  206.       cp = stpcpy (cp, territory);
  207.     }
  208.   if ((mask & XPG_CODESET) != 0)
  209.     {
  210.       *cp++ = '.';
  211.       cp = stpcpy (cp, codeset);
  212.     }
  213.   if ((mask & XPG_NORM_CODESET) != 0)
  214.     {
  215.       *cp++ = '.';
  216.       cp = stpcpy (cp, normalized_codeset);
  217.     }
  218.   if ((mask & (XPG_MODIFIER | CEN_AUDIENCE)) != 0)
  219.     {
  220.       /* This component can be part of both syntaces but has different
  221.      leading characters.  For CEN we use `+', else `@'.  */
  222.       *cp++ = (mask & CEN_AUDIENCE) != 0 ? '+' : '@';
  223.       cp = stpcpy (cp, modifier);
  224.     }
  225.   if ((mask & CEN_SPECIAL) != 0)
  226.     {
  227.       *cp++ = '+';
  228.       cp = stpcpy (cp, special);
  229.     }
  230.   if ((mask & CEN_SPONSOR) != 0)
  231.     {
  232.       *cp++ = ',';
  233.       cp = stpcpy (cp, sponsor);
  234.     }
  235.   if ((mask & CEN_REVISION) != 0)
  236.     {
  237.       *cp++ = '_';
  238.       cp = stpcpy (cp, revision);
  239.     }
  240.  
  241.   *cp++ = '/';
  242.   stpcpy (cp, filename);
  243.  
  244.   /* Look in list of already loaded domains whether it is already
  245.      available.  */
  246.   last = NULL;
  247.   for (retval = *l10nfile_list; retval != NULL; retval = retval->next)
  248.     if (retval->filename != NULL)
  249.       {
  250.     int compare = strcmp (retval->filename, abs_filename);
  251.     if (compare == 0)
  252.       /* We found it!  */
  253.       break;
  254.     if (compare < 0)
  255.       {
  256.         /* It's not in the list.  */
  257.         retval = NULL;
  258.         break;
  259.       }
  260.  
  261.     last = retval;
  262.       }
  263.  
  264.   if (retval != NULL || do_allocate == 0)
  265.     {
  266.       free (abs_filename);
  267.       return retval;
  268.     }
  269.  
  270.   retval = (struct loaded_l10nfile *)
  271.     malloc (sizeof (*retval) + (__argz_count (dirlist, dirlist_len)
  272.                 * (1 << pop (mask))
  273.                 * sizeof (struct loaded_l10nfile *)));
  274.   if (retval == NULL)
  275.     return NULL;
  276.  
  277.   retval->filename = abs_filename;
  278.   retval->decided = (__argz_count (dirlist, dirlist_len) != 1
  279.              || ((mask & XPG_CODESET) != 0
  280.              && (mask & XPG_NORM_CODESET) != 0));
  281.   retval->data = NULL;
  282.  
  283.   if (last == NULL)
  284.     {
  285.       retval->next = *l10nfile_list;
  286.       *l10nfile_list = retval;
  287.     }
  288.   else
  289.     {
  290.       retval->next = last->next;
  291.       last->next = retval;
  292.     }
  293.  
  294.   entries = 0;
  295.   /* If the DIRLIST is a real list the RETVAL entry correcponds not to
  296.      a real file.  So we have to use the DIRLIST separation machanism
  297.      of the inner loop.  */
  298.   cnt = __argz_count (dirlist, dirlist_len) == 1 ? mask - 1 : mask;
  299.   for (; cnt >= 0; --cnt)
  300.     if ((cnt & ~mask) == 0
  301.     && ((cnt & CEN_SPECIFIC) == 0 || (cnt & XPG_SPECIFIC) == 0)
  302.     && ((cnt & XPG_CODESET) == 0 || (cnt & XPG_NORM_CODESET) == 0))
  303.       {
  304.     /* Iterate over all elements of the DIRLIST.  */
  305.     char *dir = NULL;
  306.  
  307.     while ((dir = __argz_next ((char *) dirlist, dirlist_len, dir))
  308.            != NULL)
  309.       retval->successor[entries++]
  310.         = _nl_make_l10nflist (l10nfile_list, dir, strlen (dir) + 1, cnt,
  311.                   language, territory, codeset,
  312.                   normalized_codeset, modifier, special,
  313.                   sponsor, revision, filename, 1);
  314.       }
  315.   retval->successor[entries] = NULL;
  316.  
  317.   return retval;
  318. }
  319.  
  320. /* Normalize codeset name.  There is no standard for the codeset
  321.    names.  Normalization allows the user to use any of the common
  322.    names.  */
  323. const char *
  324. _nl_normalize_codeset (codeset, name_len)
  325.      const char *codeset;
  326.      size_t name_len;
  327. {
  328.   int len = 0;
  329.   int only_digit = 1;
  330.   char *retval;
  331.   char *wp;
  332.   size_t cnt;
  333.  
  334.   for (cnt = 0; cnt < name_len; ++cnt)
  335.     if (isalnum (codeset[cnt]))
  336.       {
  337.     ++len;
  338.  
  339.     if (isalpha (codeset[cnt]))
  340.       only_digit = 0;
  341.       }
  342.  
  343.   retval = (char *) malloc ((only_digit ? 3 : 0) + len + 1);
  344.  
  345.   if (retval != NULL)
  346.     {
  347.       if (only_digit)
  348.     wp = stpcpy (retval, "ISO");
  349.       else
  350.     wp = retval;
  351.  
  352.       for (cnt = 0; cnt < name_len; ++cnt)
  353.     if (isalpha (codeset[cnt]))
  354.       *wp++ = tolower (codeset[cnt]);
  355.     else if (isdigit (codeset[cnt]))
  356.       *wp++ = codeset[cnt];
  357.  
  358.       *wp = '\0';
  359.     }
  360.  
  361.   return (const char *) retval;
  362. }
  363.  
  364.  
  365. /* @@ begin of epilog @@ */
  366.  
  367. /* We don't want libintl.a to depend on any other library.  So we
  368.    avoid the non-standard function stpcpy.  In GNU C Library this
  369.    function is available, though.  Also allow the symbol HAVE_STPCPY
  370.    to be defined.  */
  371. #if !_LIBC && !HAVE_STPCPY
  372. static char *
  373. stpcpy (dest, src)
  374.      char *dest;
  375.      const char *src;
  376. {
  377.   while ((*dest++ = *src++) != '\0')
  378.     /* Do nothing. */ ;
  379.   return dest - 1;
  380. }
  381. #endif
  382.